<template>
    <div class="component-datepicker">
        <div class="component-datepick__box" @click="showCheck">
            <span
                class="component-datepick__value"
                :style='{color:color}'>
                {{ value || placeholder }}
            </span>
            <span class="component-detepick__clear iconfont icon-close-pure" :style='{color:color}' @click.stop='clearCheck'></span>
        </div>
        <transition name='component-datepicker'>
            <div class="component-datepicker__overlay" v-if="showInfo.check" @click="dismiss($event)" v-bind:style="{'background' : option.overlayOpacity? 'rgba(0,0,0,'+option.overlayOpacity+')' : 'rgba(0,0,0,0.5)'}">
                <div class="component-datepicker__body" :style="{'background-color': option.color ? option.color.header : '#3f51b5'}">
                    <div class="cov-date-monthly">
                        <div class="cov-date-previous" @click="nextMonth('pre')">芦</div>
                        <div class="cov-date-caption" :style="{'color': option.color ? option.color.headerText : '#fff'}">
                            <span @click="showYear"><small>{{checked.year}}</small></span>
                            <span @click="showMonth">{{displayInfo.month}}</span>
                        </div>
                        <div class="cov-date-next" @click="nextMonth('next')">禄</div>
                    </div>
                    <div class="cov-date-box" v-if="showInfo.day">
                        <div class="cov-picker-box">
                            <div class="week">
                                <ul>
                                    <li v-for="weekie in library.week">{{weekie}}</li>
                                </ul>
                            </div>
                            <div class="day" v-for="day in dayList" track-by="$index" @click="checkDay(day)" :class="{'checked':day.checked,'unavailable':day.unavailable,'passive-day': !(day.inMonth)}" :style="day.checked ? (option.color && option.color.checkedDay ? { background: option.color.checkedDay } : { background: '#00B1B3' }) : {}">{{day.value}}</div>
                        </div>
                    </div>
                    <div class="cov-date-box list-box" v-if="showInfo.year">
                        <div class="cov-picker-box date-list" id="yearList">
                            <div class="date-item" v-for="yearItem in library.year" track-by="$index" @click="setYear(yearItem)">{{yearItem}}</div>
                        </div>
                    </div>
                    <div class="cov-date-box list-box" v-if="showInfo.month">
                        <div class="cov-picker-box date-list">
                            <div class="date-item" v-for="monthItem in library.month" track-by="$index" @click="setMonth(monthItem)">{{monthItem}}</div>
                        </div>
                    </div>
                    <div class="cov-date-box list-box" v-if="showInfo.hour">
                        <div class="cov-picker-box date-list">
                            <div class="watch-box">
                                <div class="hour-box">
                                    <div class="mui-pciker-rule mui-pciker-rule-ft"></div>
                                    <ul>
                                        <li class="hour-item" v-for="hitem in hours" @click="setTime('hour', hitem, hours)" :class="{'active':hitem.checked}">{{hitem.value}}</li>
                                    </ul>
                                </div>
                                <div class="min-box">
                                    <div class="mui-pciker-rule mui-pciker-rule-ft"></div>
                                    <div class="min-item" v-for="mitem in mins" @click="setTime('min',mitem, mins)" :class="{'active':mitem.checked}">{{mitem.value}}</div>
                                </div>
                            </div>
                        </div>
                    </div>
                    <div class="button-box">
                        <span @click="showInfo.check=false">{{option.buttons? option.buttons.cancel : 'Cancel' }}</span>
                        <span @click="picked">{{option.buttons? option.buttons.ok : 'Ok'}}</span>
                    </div>
                </div>
            </div>
        </transition>
    </div>
</template>

<script>
import moment from 'moment'
export default {
    props: {
        required: false,
        value: {
            type: [String,Number],
            required: true
        },
        placeholder: {
            type: String,
            default: ''
        },
        color:{
            type: String,
            default: '#00B1B3'
        },
        option: {
            type: Object,
            default () {
                return {
                    type: 'day',
                    SundayFirst: false,
                    week: ['周一', '周二', '周三', '周四', '周五', '周六', '周日'],
                    month: ['一月', '二月', '三月', '四月', '五月', '六月', '七月', '八月', '九月', '十月', '十一月', '十二月'],
                    format: 'YYYY-MM-DD',
                    color: {
                        checked: '#00B1B3',
                        header: '#00B1B3',
                        headerText: '#fff'
                    },
                    inputStyle: {
                        'display': 'inline-block',
                        'padding': '6px',
                        'line-height': '22px',
                        'font-size': '16px',
                        'border': '2px solid #fff',
                        'box-shadow': '0 1px 3px 0 rgba(0, 0, 0, 0.2)',
                        'border-radius': '2px',
                        'color': '#5F5F5F'
                    },
                    buttons: {
                        ok: '确认',
                        cancel: '取消'
                    },
                    overlayOpacity: 0.5,
                    dismissible: true
                }
            }
        },
        limit: {
            type: Array,
            default () {
                return []
            }
        }
    },
    data() {
        function hours() {
            let list = []
            let hour = 24
            while (hour > 0) {
                hour--
                list.push({
                    checked: false,
                    value: hour < 10 ? '0' + hour : hour
                })
            }
            return list
        }

        function mins() {
            let list = []
            let min = 60
            while (min > 0) {
                min--
                list.push({
                    checked: false,
                    value: min < 10 ? '0' + min : min
                })
            }
            return list
        }
        return {
            hours: hours(),
            mins: mins(),
            showInfo: {
                hour: false,
                day: false,
                month: false,
                year: false,
                check: false
            },
            displayInfo: {
                month: ''
            },
            library: {
                week: this.option.week,
                month: this.option.month,
                year: []
            },
            checked: {
                oldtime: '',
                currentMoment: null,
                year: '',
                month: '',
                day: '',
                hour: '00',
                min: '00'
            },
            dayList: [],
            selectedDays: []
        }
    },
    methods: {
        pad(n) {
            n = Math.floor(n)
            return n < 10 ? '0' + n : n
        },
        nextMonth(type) {
            let next = null
            type === 'next' ? next = moment(this.checked.currentMoment).add(1, 'M') : next = moment(this.checked.currentMoment).add(-1, 'M')
            this.showDay(next)
        },
        showDay(time) {
            if (time === undefined || !Date.parse(time)) {
                this.checked.currentMoment = moment()
            } else {
                this.checked.currentMoment = moment(time, this.option.format)
            }
            this.showOne('day')
            this.checked.year = moment(this.checked.currentMoment).format('YYYY')
            this.checked.month = moment(this.checked.currentMoment).format('MM')
            this.checked.day = moment(this.checked.currentMoment).format('DD')
            this.displayInfo.month = this.library.month[moment(this.checked.currentMoment).month()]
            let days = []
            let currentMoment = this.checked.currentMoment
            let firstDay = moment(currentMoment).date(1).day()
                // gettting previous and next month
                // let currentMonth = moment(currentMoment)
            let previousMonth = moment(currentMoment)
            let nextMonth = moment(currentMoment)
            nextMonth.add(1, 'months')
            previousMonth.subtract(1, 'months')
            let monthDays = moment(currentMoment).daysInMonth()
            let oldtime = this.checked.oldtime
            for (let i = 1; i <= monthDays; ++i) {
                days.push({
                    value: i,
                    inMonth: true,
                    unavailable: false,
                    checked: false,
                    moment: moment(currentMoment).date(i)
                })
                if (i === Math.ceil(moment(currentMoment).format('D')) && moment(oldtime, this.option.format).year() === moment(currentMoment).year() && moment(oldtime, this.option.format).month() === moment(currentMoment).month()) {
                    days[i - 1].checked = true
                }
                this.checkBySelectDays(i, days)
            }
            if (firstDay === 0) firstDay = 7
            for (let i = 0; i < firstDay - (this.option.SundayFirst ? 0 : 1); i++) {
                let passiveDay = {
                    value: previousMonth.daysInMonth() - (i),
                    inMonth: false,
                    action: 'previous',
                    unavailable: false,
                    checked: false,
                    moment: moment(currentMoment).date(1).subtract(i + 1, 'days')
                }
                days.unshift(passiveDay)
            }
            var passiveDaysAtFinal = 42 - days.length
            for (let i = 1; i <= passiveDaysAtFinal; i++) {
                let passiveDay = {
                    value: i,
                    inMonth: false,
                    action: 'next',
                    unavailable: false,
                    checked: false,
                    moment: moment(currentMoment).add(1, 'months').date(i)
                }
                days.push(passiveDay)
            }
            if (this.limit.length > 0) {
                for (let li of this.limit) {
                    switch (li.type) {
                        case 'fromto':
                            days = this.limitFromTo(li, days)
                            break
                        case 'weekday':
                            days = this.limitWeekDay(li, days)
                            break
                    }
                }
            }
            this.dayList = days
        },
        checkBySelectDays(d, days) {
            this.selectedDays.forEach(day => {
                if (this.checked.year === moment(day).format('YYYY') && this.checked.month === moment(day).format('MM') && d === Math.ceil(moment(day).format('D'))) {
                    days[d - 1].checked = true
                }
            })
        },
        limitWeekDay(limit, days) {
            days.map((day) => {
                if (limit.available.indexOf(Math.floor(day.moment.format('d'))) === -1) {
                    day.unavailable = true
                }
            })
            return days
        },
        limitFromTo(limit, days) {
            if (limit.from || limit.to) {
                days.map((day) => {
                    if (this.getLimitCondition(limit, day)) {
                        day.unavailable = true
                    }
                })
            }
            return days
        },
        getLimitCondition(limit, day) {
            let tmpMoment = moment(day.moment.year() + '-' + this.pad(day.moment.month() + 1) + '-' + this.pad(day.value))
            if (limit.from && !limit.to) {
                return !tmpMoment.isAfter(limit.from)
            } else if (!limit.from && limit.to) {
                return !tmpMoment.isBefore(limit.to)
            } else {
                return !tmpMoment.isBetween(limit.from, limit.to)
            }
        },
        checkDay(obj) {
            if (obj.unavailable || obj.value === '') {
                return false
            }
            if (!(obj.inMonth)) {
                this.nextMonth(obj.action)
            }
            if (this.option.type === 'day' || this.option.type === 'min') {
                this.dayList.forEach((x) => {
                    x.checked = false
                })
                this.checked.day = this.pad(obj.value)
                obj.checked = true
            } else {
                let day = this.pad(obj.value)
                let ctime = this.checked.year + '-' + this.checked.month + '-' + day
                if (obj.checked === true) {
                    obj.checked = false
                    this.selectedDays.$remove(ctime)
                } else {
                    this.selectedDays.push(ctime)
                    obj.checked = true
                }
            }
            switch (this.option.type) {
                case 'day':
                    this.picked()
                    break
                case 'min':
                    this.showOne('hour')
                        // shift activated time items to visible position.
                    this.shiftActTime()
                    break
            }
        },
        showYear() {
            let year = moment(this.checked.currentMoment).year()
            this.library.year = []
            let yearTmp = []
            for (let i = year - 100; i < year + 5; ++i) {
                yearTmp.push(i)
            }
            this.library.year = yearTmp
            this.showOne('year')
            this.$nextTick(() => {
                let listDom = document.getElementById('yearList')
                listDom.scrollTop = (listDom.scrollHeight - 100)
                this.addYear()
            })
        },
        showOne(type) {
            switch (type) {
                case 'year':
                    this.showInfo.hour = false
                    this.showInfo.day = false
                    this.showInfo.year = true
                    this.showInfo.month = false
                    break
                case 'month':
                    this.showInfo.hour = false
                    this.showInfo.day = false
                    this.showInfo.year = false
                    this.showInfo.month = true
                    break
                case 'day':
                    this.showInfo.hour = false
                    this.showInfo.day = true
                    this.showInfo.year = false
                    this.showInfo.month = false
                    break
                case 'hour':
                    this.showInfo.hour = true
                    this.showInfo.day = false
                    this.showInfo.year = false
                    this.showInfo.month = false
                    break
                default:
                    this.showInfo.day = true
                    this.showInfo.year = false
                    this.showInfo.month = false
                    this.showInfo.hour = false
            }
        },
        showMonth() {
            this.showOne('month')
        },
        addYear() {
            let listDom = document.getElementById('yearList')
            listDom.addEventListener('scroll', (e) => {
                if (listDom.scrollTop < listDom.scrollHeight - 100) {
                    let len = this.library.year.length
                    let lastYear = this.library.year[len - 1]
                    this.library.year.push(lastYear + 1)
                }
            }, false)
        },
        setYear(year) {
            this.checked.currentMoment = moment(year + '-' + this.checked.month + '-' + this.checked.day)
            this.showDay(this.checked.currentMoment)
        },
        setMonth(month) {
            let mo = (this.library.month.indexOf(month) + 1)
            if (mo < 10) {
                mo = '0' + '' + mo
            }
            this.checked.currentMoment = moment(this.checked.year + '-' + mo + '-' + this.checked.day)
            this.showDay(this.checked.currentMoment)
        },
        showCheck() {
            if (this.value === '') {
                this.showDay()
            } else {
                if (this.option.type === 'day' || this.option.type === 'min') {
                    this.checked.oldtime = this.value
                    this.showDay(this.value)
                } else {
                    this.selectedDays = JSON.parse(this.value)
                    if (this.selectedDays.length) {
                        this.checked.oldtime = this.selectedDays[0]
                        this.showDay(this.selectedDays[0])
                    } else {
                        this.showDay()
                    }
                }
            }
            this.showInfo.check = true
        },
        clearCheck() {
            this.$emit('input', '')
        },
        setTime(type, obj, list) {
            for (let item of list) {
                item.checked = false
                if (item.value === obj.value) {
                    item.checked = true
                    this.checked[type] = item.value
                }
            }
        },
        picked() {
            let date
            if (this.option.type === 'day' || this.option.type === 'min') {
                let ctime = this.checked.year + '-' + this.checked.month + '-' + this.checked.day + ' ' + this.checked.hour + ':' + this.checked.min
                this.checked.currentMoment = moment(ctime, 'YYYY-MM-DD HH:mm')
                date = moment(this.checked.currentMoment).format(this.option.format)
            } else {
                date = JSON.stringify(this.selectedDays)
            }
            this.showInfo.check = false
            this.$emit('input', date)
        },
        dismiss(evt) {
            if (evt.target.className === 'component-datepicker__overlay') {
                if (this.option.dismissible === undefined || this.option.dismissible) {
                    this.showInfo.check = false
                    this.$emit('cancel')
                }
            }
        },
        shiftActTime() {
            // shift activated time items to visible position.
            this.$nextTick(() => {
                if (!document.querySelector('.hour-item.active')) {
                    return false
                }
                document.querySelector('.hour-box').scrollTop = (document.querySelector('.hour-item.active').offsetTop || 0) - 250
                document.querySelector('.min-box').scrollTop = (document.querySelector('.min-item.active').offsetTop || 0) - 250
            })
        }
    }
}
</script>
<style lang='scss'>
    @import "../sass/variables";
    @import "../sass/extends";
    @import "../sass/mixins";
    .component-datepicker {
      display: block;
      width: 100%;
      color: #5D5D5D;
    }
    .component-datepicker__overlay {
      transition:opacity ease 200ms;
      position: fixed;
      line-height: 1;
      width: 100%;
      height: 100%;
      z-index: 998;
      top: 0;
      left: 0;
        .component-datepicker__body {
            transition:all ease 200ms;
            display: block;
            background: #3F51B5;
            overflow: hidden;
            position: relative;
            font-size: 16px;
            position: fixed;
            display: block;
            width: 400px;
            max-width: 100%;
            z-index: 999;
            top: 50%;
            left: 50%;
            transform: translate(-50%, -50%);
        }
        .cov-picker-box {
            background: #fff;
            width: 100%;
            display: inline-block;
            padding: 25px;
            box-sizing: border-box !important;
            width: 400px;
            max-width: 100%;
            height: 280px;
            text-align: start!important;
        }
        .cov-picker-box td {
            height: 34px;
            width: 34px;
            padding: 0;
            line-height: 34px;
            color: #000;
            background: #fff;
            text-align: center;
            cursor: pointer;
        }
        .cov-picker-box td:hover {
            background: #E6E6E6;
        }
        table {
            border-collapse: collapse;
            border-spacing: 0;
            width: 100%;
        }
        .day {
            width: 14.2857143%;
            display: inline-block;
            text-align: center;
            cursor: pointer;
            height: 34px;
            padding: 0;
            line-height: 34px;
            color: #000;
            background: #fff;
            vertical-align: middle;
            transition:background ease 250ms;
            border-radius:2px;
        }
        .week ul {
            margin: 0 0 8px;
            padding: 0;
            list-style: none;
        }
        .week ul li {
            width: 14.2%;
            display: inline-block;
            text-align: center;
            background: transparent;
            color: #000;
            font-weight: bold;
        }
        .passive-day {
          /*pointer-events: none;*/
          /*opacity:0;*/
            color: #bbb;
        }
        .checked {
            background: $green;
            color: #FFF !important;
            border-radius: 2px;
        }
        .unavailable {
            color: #ccc;
            cursor: not-allowed;
        }
        .cov-date-monthly {
            height: 150px;
        }
        .cov-date-monthly > div {
            display: inline-block;
            padding: 0;
            margin: 0;
            vertical-align: middle;
            color: #fff;
            height: 150px;
            float: left;
            text-align: center;
            cursor: pointer;
        }
        .cov-date-previous,
        .cov-date-next {
            position: relative;
            width: 20% !important;
            text-indent: -300px;
            overflow: hidden;
            color: #fff;
        }
        .cov-date-caption {
            width: 60%;
            padding: 50px 0!important;
            box-sizing: border-box;
            font-size: 24px;
        }
        .cov-date-caption span{
            padding-top: 5px;
            display: block;
        }
        .cov-date-caption span:first-child{
            padding-top: 0;
        }
        .cov-date-caption span:hover {
            color: rgba(255, 255, 255, 0.7);
        }
        .cov-date-previous:hover,
        .cov-date-next:hover {
            background: rgba(255, 255, 255, 0.1);
        }
        .day:hover {
            background: #EAEAEA;
        }
        .unavailable:hover {
            background: none;
        }
        .checked:hover {
            background: #FF4F8E;
        }
        .cov-date-next::before,
        .cov-date-previous::before {
            width: 20px;
            height: 2px;
            text-align: center;
            position: absolute;
            background: #fff;
            top: 50%;
            margin-top: -7px;
            margin-left: -7px;
            left: 50%;
            line-height: 0;
            content: '';
            transform: rotate(45deg);
        }
        .cov-date-next::after,
        .cov-date-previous::after {
            width: 20px;
            height: 2px;
            text-align: center;
            position: absolute;
            background: #fff;
            margin-top: 6px;
            margin-left: -7px;
            top: 50%;
            left: 50%;
            line-height: 0;
            content: '';
            transform: rotate(-45deg);
        }
        .cov-date-previous::after {
          transform: rotate(45deg);
        }
        .cov-date-previous::before {
            transform: rotate(-45deg);
        }
        .date-item {
            text-align: center;
            font-size: 20px;
            padding: 10px 0;
            cursor: pointer;
        }
        .date-item:hover {
            background: #e0e0e0;
        }
        .date-list {
            overflow: auto;
            vertical-align: top;
            padding: 0;
        }
        .button-box {
            background: #fff;
            vertical-align: top;
            height: 50px;
            line-height: 50px;
            text-align: right;
            padding-right: 10px;
        }
        .button-box span {
            cursor: pointer;
            color:$green;
            padding: 10px 20px;
            transition:all ease 250ms;
            border-radius:2px;
            &:hover{
                background-color: $grayLight;
            }
        }
        .watch-box {
            height: 100%;
            overflow: hidden;
        }
        .hour-box,
        .min-box {
            display: inline-block;
            width: 50%;
            text-align: center;
            height: 100%;
            overflow: auto;
            float: left;
        }
        .hour-box ul,
        .min-box ul {
            list-style: none;
            margin: 0;
            padding: 0;
        }
        .hour-item,
        .min-item {
            padding: 10px;
            font-size: 36px;
            cursor: pointer;
        }
        .hour-item:hover,
        .min-item:hover {
            background: #E3E3E3;
        }
        .hour-box .active,
        .min-box .active {
            background: #F50057;
            color: #FFF !important;
        }
        ::-webkit-scrollbar {
          width: 2px;
        }
        ::-webkit-scrollbar-track {
          background: #E3E3E3;
        }
        ::-webkit-scrollbar-thumb {
            background: #C1C1C1;
            border-radius: 2px;
        }
    }
    .component-datepick__box {
        position: relative;
        width: 100%;
    }
    .component-datepick__value{
        display: block;
    }
    .component-detepick__clear{
        cursor:pointer;
        position: absolute;
        right:8px;
        top:50%;
        font-size: 13px;
        margin-top:-6.5px;
        line-height: 1;
        color:$green;
        &:hover{
            color:$defaultColor;
        }
    }
    .component-datepicker-enter {
        opacity: 0;
    }

    .component-datepicker-leave-active {
        opacity: 0;
    }
    .component-datepicker-enter .component-datepicker__body,
    .component-datepicker-leave-active .component-datepicker__body {
        transform: translate(-50%,-50%) scale(.95);
    }
</style>